package ar.edu.itba.it.cg.grupo01.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import javax.vecmath.Point3f;

import ar.edu.itba.it.cg.grupo01.api.Intersection;
import ar.edu.itba.it.cg.grupo01.api.shape.Shape;

public class CompositeIntersection implements Intersection<Shape> {

	private HashSet<Intersection<? extends Shape>> intersections;

	public CompositeIntersection(
			Set<Intersection<? extends Shape>> intersections) {
		this.intersections = new HashSet<Intersection<? extends Shape>>(
				intersections);
	}

	@Override
	public Point3f closestTo(Point3f origin) {

		List<Point3f> closests = new ArrayList<Point3f>();

		for (Intersection<? extends Shape> intersection : intersections) {
			if (intersection.intersects()) {
				closests.add(intersection.closestTo(origin));
			}
		}

		Point3f answer = null;
		float currentDistance = Float.MAX_VALUE;

		for (Point3f point : closests) {
			float distance = point.distance(origin);

			if (distance < currentDistance) {
				currentDistance = distance;
				answer = point;
			}
		}

		return answer == null ? null : (Point3f) answer.clone();
	}

	@Override
	public float distance(Point3f point) {
		List<Float> distances = new ArrayList<Float>();

		for (Intersection<? extends Shape> intersection : intersections) {
			if (intersection.intersects()) {
				distances.add(intersection.distance(point));
			}
		}

		return Collections.min(distances);
	}

	@Override
	public Set<Point3f> getIntersections() {
		Set<Point3f> ints = new HashSet<Point3f>();

		for (Intersection<? extends Shape> intersection : intersections) {
			if (intersection.intersects()) {
				ints.addAll(intersection.getIntersections());
			}
		}

		return ints;
	}

	@Override
	public Intersection<? extends Shape> getClosestIntersectionTo(Point3f point) {

		Intersection<? extends Shape> result = null;
		float distance = Float.MAX_VALUE;
		for (Intersection<? extends Shape> intersection : intersections) {

			if (intersection.intersects()) {
				Intersection<? extends Shape> realOne = intersection
						.getClosestIntersectionTo(point);
				float currentDistance = realOne.distance(point);

				if (currentDistance < distance) {
					distance = currentDistance;
					result = realOne;
				}
			}

		}

		return result;

	}

	@Override
	public boolean intersects() {

		for (Intersection<? extends Shape> intersection : intersections) {
			if (intersection.intersects()) {
				return true;
			}
		}

		return false;
	}

	@Override
	public Shape getObject() {
		throw new UnsupportedOperationException("Cannot return object");
	}

	@Override
	public Intersection.Type getType() {
		throw new UnsupportedOperationException("Cannot return type");
	}

	@Override
	public void setType(Intersection.Type type) {
		throw new UnsupportedOperationException("Cannot set type");

	}

	@Override
	public void getDetails(Shape shape, RayTraceInformation info, float delta,
			Details details) {
		throw new UnsupportedOperationException("Cannot get details");
	}

}
